package top.lshaci.learning.netty.rpc.comsumer;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;

/**
 * NettyRpcClientHandler
 *
 * @author lshaci
 * @since 1.0.0
 */
@Slf4j
public class NettyRpcClientHandler extends ChannelInboundHandlerAdapter implements Callable<Object> {

    private ChannelHandlerContext context;
    /**
     * 返回的结果
     */
    private String result;
    /**
     * 客户端调用方法时，传入的参数
     */
    private String para;

    /**
     * 与服务器的连接创建后，就会被调用，这个方法是第一个被调用(1)
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.debug("channelActive 被调用");
        context = ctx;
    }

    /**
     * 收到服务器的数据收，调用方法(4)
     */
    @Override
    public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.debug("channelRead 被调用");
        result = msg.toString();
        notify();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * 被代理对象调用，发送数据给服务器 -> wait -> 等待被唤醒(channelRead) -> 返回结果(3) -> 5
     */
    @Override
    public synchronized Object call() throws Exception {
        log.debug("call 1 被调用");
        context.writeAndFlush(para);
        System.err.println("请求调用了");
        // 进行wait, 等待channelRead方法获取到服务器的结果后唤醒
        wait();
        log.debug("call 2 被调用");

        // 服务方返回的结果
        return result;
    }

    /**
     * (2)
     */
    void setPara(String para) {
        log.debug("setPara: {}", para);
        this.para = para;
    }
}
